package com.heima.media.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.dto.ResponseResult;
import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.common.minio.MinIOService;
import com.heima.common.util.SensitiveWordUtil;
import com.heima.media.dto.ArticleDto;
import com.heima.media.dto.ContentDto;
import com.heima.media.dto.ImageDto;
import com.heima.media.entity.WmChannel;
import com.heima.media.entity.WmNews;
import com.heima.media.entity.WmSensitive;
import com.heima.media.entity.WmUser;
import com.heima.media.feign.ArticleFeign;
import com.heima.media.service.*;
import org.apache.commons.io.IOUtils;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.InputStream;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

@Service
public class AuditServiceImpl implements IAuditService {

    @Autowired
    private IWmNewsService newsService;

    @Autowired
    private GreenTextScan textScan;

    @Autowired
    private GreenImageScan imageScan;

    @Override
    public void audit(Integer id) {
        // 根据id查询自媒体文章
        WmNews wmNews = newsService.getById(id);
        audit(wmNews);
    }

    @Override
    @Async
    public void audit(WmNews wmNews) {
        System.out.println(Thread.currentThread().getName() + " 开始执行自动审核...");
        // 如果文章的状态为 4 或者 8 ,这个时候只需要判断发布时间是否大于当前时间
        if (wmNews.getStatus() == 4 || wmNews.getStatus() == 8) {
            if (wmNews.getPublishTime().getTime() <= System.currentTimeMillis()) {
                saveArticle(wmNews);
            } else {
                // 发布延迟任务
                long time = wmNews.getPublishTime().getTime();
                long delayTime = time - System.currentTimeMillis();
                // 发布延迟消息
                RBlockingQueue<String> blockingQueue = redissonClient.getBlockingQueue("article-publish");
                RDelayedQueue<String> delayedQueue = redissonClient.getDelayedQueue(blockingQueue);
                delayedQueue.offer(wmNews.getId().toString(), delayTime, TimeUnit.MILLISECONDS);
            }
            return;
        }
        // 只有文章状态为1 -待审核  这个时候进入到自动审核的流程
        if (wmNews.getStatus() == 1) {
            // 从内容中提取文本和图片
            Map<String, Object> map = getTextAndImageFromContent(wmNews.getContent());
            // 文本
            String text = wmNews.getTitle() + (String) map.get("text");
            // 图片
            List<String> images = (List<String>) map.get("images");
            // 获取封面图片
            String json = wmNews.getImages();
            List<ImageDto> coverImages = JSON.parseArray(json, ImageDto.class);
            for (ImageDto coverImage : coverImages) {
                if (!images.contains(coverImage.getUrl())) {
                    images.add(coverImage.getUrl());
                }
            }

            // 自管理敏感词过滤
            boolean sensitiveResult = checkSensitive(text, wmNews);
            if (!sensitiveResult) {
                return;
            }
            // 阿里云文本审核
            boolean textResult = checkText(text, wmNews);
            // 阿里云图片审核
            if (!textResult) return;
            boolean imageResult = checkImage(images, wmNews);
            // 审核通过,远程调用文章微服务保存文章
            if (!imageResult) return;
            // 需要判断文章的发布时间是否大于当前时间,如果发布时间大于当前时间,不是直接发布文章,而是需要等到定义的发布时间再去发布
            // todo 后期通过延迟消息队列实时发布文章
            if (wmNews.getPublishTime().getTime() <= System.currentTimeMillis()) {
                saveArticle(wmNews);
            } else {
                // 审核通过,还没有到发布时间,直接把状态改为8 审核通过（待发布）
                wmNews.setStatus(8);
                newsService.updateById(wmNews);
                // 定义延迟的时间,发布时间-当前时间
                long time = wmNews.getPublishTime().getTime();
                long delayTime = time - System.currentTimeMillis();
                // 发布延迟消息
                RBlockingQueue<String> blockingQueue = redissonClient.getBlockingQueue("article-publish");
                RDelayedQueue<String> delayedQueue = redissonClient.getDelayedQueue(blockingQueue);
                delayedQueue.offer(wmNews.getId().toString(), delayTime, TimeUnit.MILLISECONDS);
            }
        }
    }

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private IWmSensitiveService sensitiveService;

    /**
     * 敏感词审核
     *
     * @param text
     * @param wmNews
     * @return
     */
    private boolean checkSensitive(String text, WmNews wmNews) {
        boolean result = false;
        // 判断敏感词工具中的map是否为空,如果为空,从数据库加载数据保存到map中
        if (SensitiveWordUtil.dictionaryMap.size() <= 0) {
            // select sensitives from wm_sensitive
            LambdaQueryWrapper<WmSensitive> query = new LambdaQueryWrapper<>();
            query.select(WmSensitive::getSensitives);
            List<String> list = sensitiveService.listObjs(query, o -> o.toString());
            // 初始化map
            SensitiveWordUtil.initMap(list);
        }
        // 审核标题
        Map<String, Integer> mapTitle = SensitiveWordUtil.matchWords(wmNews.getTitle());
        if (mapTitle.size() <= 0) {
            // 审核内容
            Map<String, Integer> mapContent = SensitiveWordUtil.matchWords(text);
            if (mapContent.size() <= 0) {
                result = true;
            } else {
                wmNews.setStatus(2);
                Set<String> keySet = mapContent.keySet();
                String join = String.join(",", keySet);
                wmNews.setReason("敏感词审核不通过: " + join);
                newsService.updateById(wmNews);
            }
        } else {
            wmNews.setStatus(2);
            Set<String> keySet = mapTitle.keySet();
            String join = String.join(",", keySet);
            wmNews.setReason("敏感词审核不通过: " + join);
            newsService.updateById(wmNews);
        }
        return result;
    }

    @Autowired
    private ArticleFeign articleFeign;

    @Autowired
    private IWmUserService userService;

    @Autowired
    private IWmChannelService channelService;

    /**
     * 保存文章
     *
     * @param wmNews
     * @return
     */
    private Long saveArticle(WmNews wmNews) {
        // 构建保存文章dto对象
        ArticleDto dto = new ArticleDto();
        BeanUtils.copyProperties(wmNews, dto);
        dto.setId(null);
        // 需要获取到作者的id
        // 作者id之前在创建自媒体用户时会从文章库的作者表中同步到自媒体账号中
        // 查询自媒体用户
        WmUser wmUser = userService.getById(wmNews.getUserId());
        dto.setAuthorId(wmUser.getApAuthorId());
        dto.setAuthorName(wmUser.getName());
        // 查询频道名称
        WmChannel wmChannel = channelService.getById(wmNews.getChannelId());
        dto.setChannelName(wmChannel.getName());
        dto.setLayout(wmNews.getType());
        dto.setFlag(0);
        // 转换图片格式 APP前端直接使用逗号分隔   http://123.jpg,http://234.jpg
        String image = "";
        String images = wmNews.getImages();
        List<ImageDto> list = JSON.parseArray(images, ImageDto.class);
        List<String> coverImages = new ArrayList<>();
        for (ImageDto imageDto : list) {
            String url = imageDto.getUrl();
            if (!StringUtils.isEmpty(url)) {
                coverImages.add(url);
            }
        }
        image = String.join(",", coverImages);
        dto.setImages(image);
        // 远程调用文章微服务接口
        ResponseResult<Long> longResponseResult = articleFeign.saveArticle(dto);
        if (longResponseResult.getCode().equals(AppHttpCodeEnum.SUCCESS.getCode())) {
            Long articleId = longResponseResult.getData();
            // 需要将文章id写回到自媒体文章表中
            if (articleId != null) {
                wmNews.setArticleId(articleId);
                wmNews.setStatus(9);
                newsService.updateById(wmNews);
            }
            return articleId;
        }
        return null;
    }

    @Autowired
    private MinIOService minIOService;

    /**
     * 阿里云图片审核
     *
     * @param images
     * @param wmNews
     * @return
     */
    private boolean checkImage(List<String> images, WmNews wmNews) {
        boolean result = false;
        // 如果没有图片,不需要进行图片审核,直接返回true
        if (images.size() <= 0) {
            return true;
        }
        try {
            // 调用阿里云图片审核
            // Map map = imageScan.checkUrl(images);    // 如果minio部署在外网服务器,可以直接通过URL地址来审核
            // 先将图片从minio服务器下载下来,然后调用阿里云进行审核
            List<byte[]> imageList = new ArrayList<>();
            for (String url : images) {
                // 下载图片
                InputStream inputStream = minIOService.download(url);
                byte[] bytes = IOUtils.toByteArray(inputStream);
                imageList.add(bytes);
            }
            Map map = imageScan.imageScan(imageList);
            String suggestion = (String) map.get("suggestion");
            // 判断结果
            switch (suggestion) {
                case "pass":
                    // 审核通过
                    result = true;
                    break;
                case "block":
                    // 审核不通过
                    wmNews.setStatus(2);
                    // 获取不通过的原因
                    String label = (String) map.get("label");
                    wmNews.setReason("阿里云图片审核不通过: " + label);
                    newsService.updateById(wmNews);
                    break;
                case "review":
                    // 人工审核
                    wmNews.setStatus(3);
                    newsService.updateById(wmNews);
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 阿里云文本审核
     *
     * @param text
     * @param wmNews
     * @return
     */
    private boolean checkText(String text, WmNews wmNews) {
        boolean result = false;
        try {
            Map map = textScan.greenTextScan(text);
            String suggestion = (String) map.get("suggestion");
            // 判断结果
            switch (suggestion) {
                case "pass":
                    // 审核通过
                    result = true;
                    break;
                case "block":
                    // 审核不通过
                    wmNews.setStatus(2);
                    // 获取不通过的原因
                    String label = (String) map.get("label");
                    wmNews.setReason("阿里云文本审核不通过: " + label);
                    newsService.updateById(wmNews);
                    break;
                case "review":
                    // 人工审核
                    wmNews.setStatus(3);
                    newsService.updateById(wmNews);
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 从文章内容中提取文本和图片
     *
     * @param content
     * @return
     */
    private Map<String, Object> getTextAndImageFromContent(String content) {
        Map<String, Object> map = new HashMap<>();
        // 定义文本内容
        StringBuilder sb = new StringBuilder();
        // 定义图片集合
        List<String> images = new ArrayList<>();
        // JSON解析内容
        List<ContentDto> contentDtos = JSON.parseArray(content, ContentDto.class);
        for (ContentDto dto : contentDtos) {
            if (dto.getType().equals("text")) {
                // 拼接文本内容
                sb.append(dto.getValue());
            } else {
                images.add(dto.getValue());
            }
        }
        map.put("text", sb.toString());
        map.put("images", images);
        return map;
    }
}
